package com.iflytek.cosmo.ocr.common.util;


import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;

import com.google.common.collect.Lists;
import com.iflytek.icourt.common.ServiceException;
import com.iflytek.icourt.common.constants.Constants;
import com.iflytek.icourt.common.enums.ResultCode;
import com.iflytek.icourt.common.util.FileUtil;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class GsUtil {
    private static final Logger logger = LoggerFactory.getLogger(GsUtil.class);

    @Value("${gs.baseurl}")
    private String gsBaseurl;

    @Value("${file.convert.path}")
    private String fileConvertPath;


    /**
     * 将PDF格式的字节数组转换为图像文件数组，每一页PDF内容生成一个图像文件
     *
     * @param namePrefix
     * @param pdf        pdf文件内容
     * @param fileExt    待转文件格式
     * @param imageExt   转图片格式
     * @param resolution 分辨率dpi
     *
     * @return 转换后的图像文件数组
     */
    public List<File> pdf2Image(String namePrefix, byte[] pdf, String password, String fileExt, String imageExt,
            Integer resolution) {
        List<String> argList = Lists
                .newArrayList(gsBaseurl, "-dSAFER", "-dBATCH", "-dNOPAUSE", "-dTextAlphaBits=4", "-dDownScaleFactor=2",
                        "-dGraphicsAlphaBits=4");
        parseDevice(argList, imageExt);
        parseResolution(pdf, password, resolution, argList);
        if (StringUtils.isNotBlank(password)) {
            argList.add("-sPDFPassword=" + password);
        }

        String suffix = "." + imageExt;
        String basePath = fileConvertPath + File.separator + namePrefix + File.separator;
        String imagePath = basePath + File.separator + "%d" + suffix;
        argList.add("-sOutputFile=" + imagePath);
        try {
            String pdfPath = byte2File(pdf, fileExt, basePath);
            argList.add(pdfPath);
            String[] gsArgs = argList.toArray(new String[0]);

            long imageStartTime = System.currentTimeMillis();
            Process proc = new ProcessBuilder(gsArgs).redirectErrorStream(true).start();
            //读取进程的流
            while (proc.isAlive()) {
                List<String> output = IOUtils.readLines(proc.getInputStream());
                output.forEach((String line) -> logger.info(line));
            }
            logger.info("图片转换用时：{}ms", (System.currentTimeMillis() - imageStartTime) / 1000);
            FileUtil.deleteFile(pdfPath);

            // 线程等待,等待处理完毕
            int exitValue;
            if ((exitValue = proc.waitFor()) != 0) {
                logger.error("pdf转为图片转换失败 gs进程返回错误码为: " + exitValue);
                throw new RuntimeException();
            }
            else {
                File imageDirectory = new File(basePath);
                File[] imageFiles = imageDirectory.listFiles(new FilenameFilter() {
                    @Override
                    public boolean accept(File dir, String name) {
                        return name.endsWith(suffix);
                    }
                });

                ArrayList<File> sortedFiles = Lists.newArrayList(imageFiles);
                sortedFiles
                        .sort(Comparator.comparingInt(f -> Integer.parseInt(FilenameUtils.getBaseName(f.getName()))));
                return sortedFiles;
            }
        }
        catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException(ResultCode.IMAGE_CONVERT_FAIL);
        }
    }

    private void parseResolution(byte[] pdf, String password, Integer resolution, List<String> argList) {
        if (resolution == null) {
            //获取总页数
            int pageCount = 1;
            try {
                PDDocument document = PDDocument.load(pdf, password);
                pageCount = document.getNumberOfPages();
                PDRectangle mediaBox = document.getPage(0).getMediaBox();
                if (pageCount > 0) {
                    float width = mediaBox.getWidth();
                    float height = mediaBox.getHeight();
                    //当分辨率是72像素/英寸时，A4纸像素长宽分别是842×595；
                    //当分辨率是120像素/英寸时，A4纸像素长宽分别是2105×1487；
                    //当分辨率是150像素/英寸时，A4纸像素长宽分别是1754×1240；
                    //当分辨率是300像素/英寸时，A4纸像素长宽分别是3508×2479
                    if (width <= 2479 && height <= 3508) {
                        resolution = 300;
                    }
                    else if (width * 0.5 <= 2479 && height * 0.5 <= 3508) {
                        resolution = 150;
                    }
                    else if (width * 0.4 <= 2479 && height * 0.4 <= 3508) {
                        resolution = 120;
                    }
                    else {
                        resolution = 72;
                    }
                    logger.info("pdf首页宽高" + width + "x" + height + "计算使用分辨率" + resolution + "dpi");
                }
            }
            catch (Exception e) {
                logger.error(e.getMessage(), e);
                throw new ServiceException(ResultCode.FILE_READ_FAIL);
            }
        }
        argList.add("-r" + resolution);
    }

    private void parseDevice(List<String> argList, String imageExt) {
        if (Constants.SupportExt.JPG.equalsIgnoreCase(imageExt) || Constants.SupportExt.JPEG.equalsIgnoreCase(imageExt)) {
            //gs中无jpg，应使用jpeg
            argList.add("-sDEVICE=" + Constants.SupportExt.JPEG);
            argList.add("-dJPEGQ=75");
        } else {
            argList.add("-sDEVICE=" + imageExt);
        }
    }

    private String byte2File(byte[] fileByte, String fileExt, String dirPath) {
        String filename = UUID.randomUUID() + "." + fileExt;
        return FileUtil.byte2File(fileByte, dirPath, filename);
    }

}
